/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package com.pearreview.util.pdf;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfAnnotation;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.pearreview.application.Messages;
import com.pearreview.util.review.Finding;
import com.pearreview.util.review.IdList;

/**
 * This class is for displaying the findings in the PDF document.
 * The findings are displayed in a table. This class is useful for the 
 * protocol of the scribe mode and the report of the reviewer mode.
 *
 */
public class PdfFindingsWriter {
	
	private Document doc;
	private PdfWriter writer;
	
	public PdfFindingsWriter(Document doc, PdfWriter writer) {
		this.doc = doc;
		this.writer = writer;
	}

	/**
	 * Writes a table with findings to the given document.
	 * If the images should be printed to the document, a reference to them
	 * will be set in the finding.
	 * 
	 * @param findings A list of findings.
	 * @param fImages A list of images to reference them with findings.
	 * @param printImages If the images should be printed to the document.
	 * @param imageNumber Current number of images.
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void writeFindings(IdList<Finding> findings, 
			ArrayList<PdfImage> fImages, boolean printImages, int imageNumber) 
			throws DocumentException, IOException {
		Chunk cHeading = new PChunk(Messages.getString(
				"PearReview.protocol.findings"));
		Font font = cHeading.getFont();
		font.setSize(20);
		
		Paragraph pHeading = new PParagraph();
		pHeading.setSpacingAfter(40);
		pHeading.add(cHeading);
			
		doc.add(pHeading);
		
		boolean images = false;
		for (int row = 0; row < findings.size(); row++) {
			Finding finding = findings.get(row);
			if (finding.getExternalReferences() != null)
				if (finding.getExternalReferences().size() > 0)
					images = true;
		}
		
		boolean aspects = false;
		for (int row = 0; row < findings.size(); row++) {
			Finding finding = findings.get(row);
			if (finding.getAspects() != null)
				if (finding.getAspects().size() > 0)
					aspects = true;
		}
		
		//create the table and table heading
		PdfPTable table = new PdfPTable(4);
		float[] widths = { 1f, 5f, 2f, 3f};
		table.setWidths(widths);
		table.setWidthPercentage(100);
		table.setHeaderRows(1);
		
		PdfPCell h1 = new PdfPCell(new PParagraph("ID"));
		h1.setBorder(0);
		h1.setGrayFill(0.7f);
		table.addCell(h1);
		
		PdfPCell h2 = new PdfPCell(new PParagraph(Messages.getString(
				"PearReview.protocol.description")));
		h2.setBorder(0);
		h2.setGrayFill(0.7f);
		table.addCell(h2);
		
		PdfPCell h3 = new PdfPCell(new PParagraph(Messages.getString(
				"PearReview.Scribe.findings.severity")));
		h3.setBorder(0);
		h3.setGrayFill(0.7f);
		table.addCell(h3);
		
		PdfPTable nestedHead = new PdfPTable(1);
		PdfPCell nestCell = new PdfPCell(new PParagraph(Messages.getString(
				"PearReview.Scribe.findings.references")));
		nestCell.setBorder(0);
		nestedHead.addCell(nestCell);
		if  (aspects) {
			nestCell = new PdfPCell(new PParagraph(Messages.getString(
					"PearReview.Scribe.findings.aspects")));
			nestCell.setBorder(0);
			nestCell.setBorderWidthTop(0.5f);
			nestCell.setBorderColorTop(new BaseColor(0xdddddd));
			nestedHead.addCell(nestCell);
		}
		if (images) {
			nestCell = new PdfPCell(new PParagraph(Messages.getString(
					"PearReview.Scribe.findings.images")));
			nestCell.setBorder(0);
			nestCell.setBorderWidthTop(0.5f);
			nestCell.setBorderColorTop(new BaseColor(0xdddddd));
			nestedHead.addCell(nestCell);
		}
		
		PdfPCell h4 = new PdfPCell(nestedHead);
		h4.setBorder(0);
		h4.setGrayFill(0.7f);
		table.addCell(h4);
		
		PdfPCell cell;
		
		
		
		//write the content of the table
		for (int row = 0; row < findings.size(); 
				row++) {
			Finding finding = findings.get(row);
			boolean gray = row % 2 == 1;
			
			
			//add id
			Chunk cId = new PChunk(finding.getId()).setLocalDestination("ID" + 
					finding.getId());
		
			cell = new PdfPCell(new PParagraph(cId));
			cell.setBorder(0);
			
			if (gray)
				cell.setGrayFill(0.9f);
			table.addCell(cell);
			
			//add description
			cell = new PdfPCell(new PParagraph(finding.getDescription()));
			cell.setBorder(0);
			
			if (gray)
				cell.setGrayFill(0.9f);
			table.addCell(cell);
			
			//add severity
			cell = new PdfPCell(new PParagraph(finding.getSeverity().getName()));
			cell.setBorder(0);
			
			if (gray)
				cell.setGrayFill(0.9f);
			table.addCell(cell);
			
			PdfPTable nested = new PdfPTable(1);
			
			
			//add references
			cell = new PdfPCell();
			cell.setBorder(0);
			
			if (gray)
				cell.setGrayFill(0.9f);
			
			if (findings.get(row).getReferences() != null && 
					finding.getReferences().size() > 0) {
				for (int i=0; i<finding.getReferences().size(); i++) {
					cell.addElement(
							new PParagraph(finding.getReferences().get(i)));
				}
			} else {
				cell.addElement(getNoReference());
			}
			cell.setPaddingBottom(5);
			nested.addCell(cell);
			
			//add aspects
			if (aspects) {
				cell = new PdfPCell();
				cell.setBorder(0);
				cell.setBorderWidthTop(0.5f);
				cell.setBorderColorTop(new BaseColor(0xaaaaaa));
				
				if (gray) {
					cell.setGrayFill(0.9f);
					cell.setBorderColorTop(new BaseColor(0xffffff));
				}
				
				if (finding.getAspects() != null && 
						finding.getAspects().size() > 0) {
					for (int i=0; i<finding.getAspects().size(); i++) {
						cell.addElement(
								new PParagraph(finding.getAspects().get(i)));
					}
				} else {
					cell.addElement(getNoReference());
				}
				cell.setPaddingBottom(5);
				nested.addCell(cell);
			}
			
			//add pictures
			if (images) {
				cell = new PdfPCell();
				cell.setBorder(0);
				cell.setBorderWidthTop(0.5f);
				cell.setBorderColorTop(new BaseColor(0xaaaaaa));
				
				if (gray) {
					cell.setGrayFill(0.9f);
					cell.setBorderColorTop(new BaseColor(0xffffff));
				}
				
				if (finding.getExternalReferences() != null && 
						finding.getExternalReferences().size() > 0) {
					for (int i=0; i<finding.getExternalReferences().size(); i++) 
					{
						String fileString = new File(finding
								.getExternalReferences().get(i)).getName();
						
						PdfAnnotation attachment = 
							PdfAnnotation.createFileAttachment(
								writer, new Rectangle(100f, 650f, 150f, 700f),
								fileString + " (" + Messages.getString(
								"PearReview.protocol.attachment_see_finding")
								+ " " + 
								finding.getId() + ")",
								getBytesFromFile(new File(finding
										.getExternalReferences().get(i))),
								null, fileString);
						
						PdfImage image = new PdfImage();
						image.setAttachment(attachment);
						image.setId(new Integer(finding.getId()));
						image.setFileName(fileString);
						image.setImage(finding.getExternalReferences()
								.get(i).toURL());
						fImages.add(image);
						
						Chunk fileName = new PChunk(fileString);
						if (printImages) {
							String goTo = "image" + imageNumber;
							fileName.setLocalGoto(goTo);
							image.setGoTo(goTo);
							imageNumber++;
						}
						Chunk attachPin = new PChunk(" - ")
								.setAnnotation(attachment);
						
						Paragraph content = new PParagraph();
						content.add(attachPin);
						content.add(new PChunk("  "));
						content.add(fileName);
						
						cell.addElement(content);
					}
				} else {
					cell.addElement(getNoReference());
				}
				cell.setPaddingBottom(5);
				nested.addCell(cell);
			}
			
			nestCell = new PdfPCell(nested);
			nestCell.setBorder(0);
			table.addCell(nestCell);
		}
		
		doc.add(table);
	}
	
	/**
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	private byte[] getBytesFromFile(File file) throws IOException {
		InputStream is = new FileInputStream(file);
		long length = file.length();
		byte[] bytes = new byte[(int) length];
		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length
				&& (numRead = is.read(bytes, offset, bytes.length - offset)) 
				>= 0) {
			offset += numRead;
		}
		if (offset < bytes.length) {
			throw new IOException("Could not completely read file "
					+ file.getName());
		}
		is.close();
		return bytes;
	}
	
	/**
	 * 
	 * @return
	 */
	private PChunk getNoReference() {
		PChunk c = new PChunk(Messages.getString("PearReview.protocol.empty"));
		c.getFont().setStyle(Font.ITALIC);
		return c;
	}
}
